#pragma once

#include <iostream>
#include "log.hpp"
#include <sys/socket.h>
#include <string>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <cstring>

using namespace Logspace;

const std::string defaultip = "0.0.0.0";

enum
{
    SOCKET_Err,
    BIND_Err,
    LISTEN_Err
};

class Sock
{
public:
    Sock()
        : sockfd_(-1)
    {
    }

    void Socket()
    {
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            Log(Fatal) << " socket failed";
            exit(SOCKET_Err);
        }
        Log(Info) << "socket sucess";
    }

    void Bind(uint16_t port)
    {
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        inet_aton(defaultip.c_str(), &server.sin_addr);

        if (bind(sockfd_, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            Log(Fatal) << " bind fail";
            exit(BIND_Err);
        }
        Log(Info) << "bind sucess";
    }

    void Listen()
    {
        if (listen(sockfd_, 10) < 0)
        {
            Log(Fatal) << " listen fail";
            exit(LISTEN_Err);
        }
        Log(Info) << "listen sucess";
    }

    int Accept()
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int fd = accept(sockfd_, (sockaddr *)&client, &len);

        return fd;
    }

    int Accept(std::string &ip, uint16_t &port)
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int fd = accept(sockfd_, (sockaddr *)&client, &len);

        port = ntohs(client.sin_port);
        char buffer[256];
        memset(buffer, sizeof(buffer), 0);
        inet_ntop(AF_INET , (void*)&client , buffer , sizeof(buffer));
        ip = buffer;

        return fd;
    }

    int Get_fd()
    {
        return sockfd_;
    }

private:
    int sockfd_;
};